package com.nervenets.web.controller;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.nervenets.utils.JodaUtils;
import com.nervenets.utils.StringUtils;
import com.nervenets.web.controller.handler.Handler;
import com.nervenets.web.controller.handler.common.TokenParams;
import com.nervenets.web.entity.MessageCode;
import com.nervenets.web.entity.UserToken;
import com.nervenets.web.enumeration.Gender;
import com.nervenets.web.enumeration.Method;
import com.nervenets.web.enumeration.OrderStatus;
import com.nervenets.web.hibernate.domain.user.Order;
import com.nervenets.web.hibernate.domain.user.User;
import com.nervenets.web.rabbitmq.FlowMessage;
import com.nervenets.web.rabbitmq.FlowType;
import com.nervenets.web.redis.utils.ISyncExecutor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.weixin4j.Configuration;
import org.weixin4j.OAuth2;
import org.weixin4j.OAuth2User;
import org.weixin4j.message.PayResult;
import org.weixin4j.util.XStreamFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * Created by Joe
 * Date: 12-12-5 下午9:24
 * Email: joesupper@vip.qq.com
 */
@Controller
@RequestMapping("/api/v1")
public class API1Controller extends APIController {

    @RequestMapping(
            value = "/{method}",
            method = {RequestMethod.GET, RequestMethod.POST},
            produces = "application/json;charset=UTF-8"
    )
    @ResponseBody
    protected String handleRequest(@PathVariable String method, HttpServletRequest request, HttpServletResponse response) throws Exception {
        Method a;
        try {
            a = Method.valueOf(method);
        } catch (Exception e) {
            return errorMessage(MessageCode.code_446);
        }
        Handler handler = a.getHandler();
        if (null == handler) return errorMessage(MessageCode.code_501);
        if (a.isDeprecated()) return errorMessage(MessageCode.code_504);
        handler.setMessageProducer(messageProducer);
        handler.setUserDao(userDao);
        handler.setGlobalService(globalService);
        handler.setGlobalVariablesService(globalVariablesService);
        handler.setRedisSyncLocker(redisSyncLocker);
        handler.setConfigProperties(configProperties);
        return handler.handleRequest(request, response);
    }

    @RequestMapping(method = RequestMethod.GET)
    protected ModelAndView index(HttpServletRequest request) throws Exception {
        String redirectUrl = ServletRequestUtils.getStringParameter(request, "url");
        String itoken = ServletRequestUtils.getStringParameter(request, "itoken");
        String[] split = redirectUrl.split("/");
        if (!redirectUrl.startsWith("http://") || split.length < 3) return message("weixin_redirect_url_error");
        String newRedirectUrl = "http://" + split[2] + "/api/v1/redirect?url=" + redirectUrl;
        if (!StringUtils.isEmpty(itoken)) {
            newRedirectUrl += "&itoken=" + itoken;
        }
        OAuth2 auth2 = new OAuth2();
        String oAuth2CodeUserInfoUrl = auth2.getOAuth2CodeUserInfoUrl(Configuration.getOAuthAppId(), newRedirectUrl);
        System.out.println(oAuth2CodeUserInfoUrl);
        return new ModelAndView("redirect:" + oAuth2CodeUserInfoUrl);
    }

    @RequestMapping(value = "/redirect", method = RequestMethod.GET)
    protected String redirect(Model model, HttpServletRequest request) throws Exception {
        try {
            String code = ServletRequestUtils.getStringParameter(request, "code");
            String redirectUrl = ServletRequestUtils.getStringParameter(request, "url", null);
            String itoken = ServletRequestUtils.getStringParameter(request, "itoken", null);
            OAuth2 auth2 = new OAuth2();
            auth2.login(Configuration.getOAuthAppId(), Configuration.getOAuthSecret(), code);
            OAuth2User userInfo = auth2.getUserInfo();

            User user = userDao.getUserByWechatId(userInfo.getOpenid());
            if (null == user) {
                user = new User();
            }
            boolean isNewUser = user.isNew();
            user.setWechatId(userInfo.getOpenid());
            user.setUnionId(userInfo.getUnionid());
            user.getInfo().setName(StringUtils.filterEmoji(userInfo.getNickname()));
            user.setAvatar(userInfo.getHeadimgurl());
            user.setGender(userInfo.getSex() == 1 ? Gender.male : Gender.female);
            if (0 == user.getInviteUserId() && !StringUtils.isEmpty(itoken)) {
                try {
                    final long inviteUserId = TokenParams.resolveToken(itoken);
                    System.out.println("inviteUserId:" + inviteUserId);
                    if (inviteUserId > 0) {
                        user.setInviteUserId(inviteUserId);
                    }
                } catch (Exception e) {
                    //
                }
            }
            /*String sceneId = globalService.getGlobalPair(userInfo.getOpenid());
            if (!StringUtils.isEmpty(sceneId)) {
                Seller seller = userDao.getSellerBySceneId(Integer.parseInt(sceneId));
                System.out.println("带参数的二维码进入系统...");
                if (null != seller) {
                    System.out.println(String.format("销售ID:%s,SceneId:%s", seller.getUserId(), seller.getSceneId()));
                    user.setSellerUserId(seller.getUserId());
                }
                globalService.deleteGlobalPair(userInfo.getOpenid());
            }*/

            userDao.saveOrUpdate(user);
            globalService.clearRedisUserStored(user.getId());
            if (isNewUser) globalService.activeUser(user.getId());
            final String tokenStr = new UserToken(user.getId(), 0).getTokenStr();
            System.out.println("token:" + tokenStr);
            System.out.println("redirectUrl:" + redirectUrl);
            model.addAttribute("token", tokenStr);
            model.addAttribute("redirectUrl", redirectUrl);

            return "views/stc/go";
        } catch (Exception e) {
            System.out.println(e.getMessage());
            model.addAttribute("message", "此页面为微信授权跳转页面，有可能由于某些原因会加载很慢，重新刷新后会过期，如果您有幸看到此提示，请关闭此页面重新进入，给您带来的不便请找微信负责！");
            return "views/stc/500";
        }
    }

    @RequestMapping(value = "/orderAliPaid", method = RequestMethod.POST)
    @ResponseBody
    protected String orderAliPaid(final HttpServletRequest request, HttpServletResponse response) throws Exception {
        //获取POST流
        Map<String, String> params = new HashMap<String, String>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
            params.put(name, valueStr);
        }
        System.out.println(JSONObject.toJSONString(params));
        final String orderNumber = ServletRequestUtils.getStringParameter(request, "out_trade_no");
        final String tradeStatus = ServletRequestUtils.getStringParameter(request, "trade_status");

        if (tradeStatus.equals("TRADE_FINISHED") || tradeStatus.equals("TRADE_SUCCESS")) {
            orderHandle(orderNumber);
            return "success";
        }
        return "fail";
    }

    @RequestMapping(value = "/orderWxPaid", method = RequestMethod.POST)
    @ResponseBody
    protected void orderWxPaid(final HttpServletRequest request, HttpServletResponse response) throws Exception {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/xml");
        //获取POST流
        String xmlMsg = XStreamFactory.inputStream2String(request.getInputStream());
        System.out.println(xmlMsg);

        ObjectMapper xmlMapper = new XmlMapper();
        xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        PayResult payResult = xmlMapper.readValue(xmlMsg, PayResult.class);

        if ("SUCCESS".equals(payResult.getReturn_code()) && "SUCCESS".equals(payResult.getResult_code())) {
            final String out_trade_no = payResult.getOut_trade_no();
            orderHandle(out_trade_no);

            response.getWriter().write("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
        }
    }


    private void orderHandle(String orderNumber) throws Exception {
        int orderId = Integer.parseInt(orderNumber.substring(12));
        redisSyncLocker.idLock(orderId, o -> {
            if (orderNumber.startsWith(Global.OrderNumber.MB)) {
                final Order order = userDao.findById(orderId, Order.class);
                if (OrderStatus.init.equals(order.getStatus())) {
                    order.setStatus(order.isOfflinePay() ? OrderStatus.tailConfirm : OrderStatus.paid);
                    order.setPayTime(JodaUtils.getTimestamp());
                    userDao.saveOrUpdate(order);

                    messageProducer.flow(new FlowMessage(order.getUserId(), FlowType.paid, 0, orderId, new Handler.KeyValue("detail", "购买影片充值")));
                    messageProducer.flow(new FlowMessage(order.getUserId(), FlowType.mvPaid, 0, orderId, new Handler.KeyValue("detail", "影片充值购买")));
                }
            } else if (orderNumber.startsWith(Global.OrderNumber.RECHARGE)) {
                final Order order = userDao.findById(orderId, Order.class);
                if (OrderStatus.init.equals(order.getStatus())) {
                    order.setStatus(OrderStatus.finish);
                    order.setPayTime(JodaUtils.getTimestamp());
                    userDao.saveOrUpdate(order);

                    messageProducer.flow(new FlowMessage(order.getUserId(), FlowType.paid, 0, orderId, new Handler.KeyValue("detail", "在线充值")));
                }
            }
            return null;
        });

    }

    @Override
    protected String version() {
        return "1.0";
    }
}
